#include <algorithm>
#include <thread>
#include <vector>

#include "../../include/helpers/thread_state_egl.h"

namespace ohos_rive {
static bool config_has_attribute(EGLDisplay display, EGLConfig config, EGLint attribute, EGLint value)
{
    EGLint outValue = 0;
    EGLBoolean result = eglGetConfigAttrib(display, config, attribute, &outValue);
    EGL_ERR_CHECK();
    return result && (outValue == value);
}

EGLThreadState::EGLThreadState()
{
    LOGI("EGLThreadState constructor called");

    m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (m_display == EGL_NO_DISPLAY) {
        EGL_ERR_CHECK();
        LOGE("eglGetDisplay() failed.");
        return;
    }
    LOGI("EGL display obtained successfully");

    EGLint majorVersion, minorVersion;
    if (!eglInitialize(m_display, &majorVersion, &minorVersion)) {
        EGL_ERR_CHECK();
        LOGE("eglInitialize() failed.");
        return;
    }
    LOGI("EGL initialized successfully, version: %{public}d.%{public}d", majorVersion, minorVersion);

    EGLint configAttributes[] = {EGL_RENDERABLE_TYPE,
                                 EGL_OPENGL_ES3_BIT, // ← 支持 ES 3.0
                                 EGL_SURFACE_TYPE,
                                 EGL_WINDOW_BIT,
                                 EGL_RED_SIZE,
                                 8,
                                 EGL_GREEN_SIZE,
                                 8,
                                 EGL_BLUE_SIZE,
                                 8,
                                 EGL_ALPHA_SIZE,
                                 8,
                                 EGL_DEPTH_SIZE,
                                 0,
                                 EGL_STENCIL_SIZE,
                                 8,
                                 EGL_NONE};

    EGLint num_configs = 0;
    if (!eglChooseConfig(m_display, configAttributes, nullptr, 0, &num_configs)) {
        EGL_ERR_CHECK();
        LOGE("eglChooseConfig() didn't find any configs");
        return;
    }
    LOGI("Found %{public}d EGL configs", num_configs);

    if (num_configs == 0) {
        LOGE("No EGL configs found");
        return;
    }

    std::vector<EGLConfig> supportedConfigs(static_cast<size_t>(num_configs));
    if (!eglChooseConfig(m_display, configAttributes, supportedConfigs.data(), num_configs, &num_configs)) {
        EGL_ERR_CHECK();
        LOGE("eglChooseConfig() failed to retrieve configs");
        return;
    }

    // Choose a config, either a match if possible or the first config otherwise
    const auto configMatches = [&](EGLConfig config) {
        if (!config_has_attribute(m_display, config, EGL_RED_SIZE, 8))
            return false;
        if (!config_has_attribute(m_display, config, EGL_GREEN_SIZE, 8))
            return false;
        if (!config_has_attribute(m_display, config, EGL_BLUE_SIZE, 8))
            return false;
        if (!config_has_attribute(m_display, config, EGL_STENCIL_SIZE, 8))
            return false;
        return config_has_attribute(m_display, config, EGL_DEPTH_SIZE, 0);
    };

    const auto configIter = std::find_if(supportedConfigs.cbegin(), supportedConfigs.cend(), configMatches);

    m_config = (configIter != supportedConfigs.cend()) ? *configIter : supportedConfigs[0];
    LOGI("EGL config selected: %p", m_config);

    const EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};

    m_context = eglCreateContext(m_display, m_config, nullptr, contextAttributes);
    if (m_context == EGL_NO_CONTEXT) {
        LOGE("eglCreateContext() failed.");
        EGL_ERR_CHECK();
        return;
    }
    LOGI("EGL context created successfully: %{public}p", m_context);
}

EGLThreadState::~EGLThreadState()
{
    LOGI("EGLThreadState destructor called");

    if (m_context != EGL_NO_CONTEXT) {
        LOGI("Destroying EGL context");
        eglDestroyContext(m_display, m_context);
        EGL_ERR_CHECK();
        m_context = EGL_NO_CONTEXT;
    }

    LOGI("Releasing EGL thread");
    eglReleaseThread();
    EGL_ERR_CHECK();

    if (m_display != EGL_NO_DISPLAY) {
        LOGI("Terminating EGL display");
        eglTerminate(m_display);
        EGL_ERR_CHECK();
        m_display = EGL_NO_DISPLAY;
    }

    LOGI("EGLThreadState destroyed successfully");
}

EGLSurface EGLThreadState::createEGLSurface(EGLNativeWindowType window)
{
    if (!window) {
        return EGL_NO_SURFACE;
    }

    EGLSurface surface = eglCreateWindowSurface(m_display, m_config, window, nullptr);
    return surface;
}

void EGLThreadState::swapBuffers()
{
    if (m_currentSurface != EGL_NO_SURFACE && m_display != EGL_NO_DISPLAY) {
        eglSwapBuffers(m_display, m_currentSurface);
    }
}

void EGLThreadState::makeCurrent(EGLSurface surface)
{
    if (surface == EGL_NO_SURFACE) {
        LOGE("makeCurrent: Invalid surface");
        return;
    }

    EGLBoolean result = eglMakeCurrent(m_display, surface, surface, m_context);
    if (result == EGL_FALSE) {
        LOGE("eglMakeCurrent failed");
        EGL_ERR_CHECK();
    } else {
        m_currentSurface = surface;
        LOGD("Surface made current: %p", surface);
    }
}
} // namespace ohos_rive